package com.melon.http;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author TianGua
 * @since 2023/7/18 - 19:32
 */
@Component
@Slf4j
public abstract class AbstractHttpRemoteHandler {

    /**
     * 设置请求体的内容类型为 application/json
     */
    public MediaType mediaType = MediaType.parse("application/json; charset=utf-8");

    public ObjectMapper objectMapper = new ObjectMapper();


    {
        objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

        // 在遇到未知属性的时候不抛出异常
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    }

    public String getDeployAddress() {
        return System.getenv("SERVICE_DEPLOY_ADDRESS");
    }

    public String getDeployPort() {
        return System.getenv("SERVICE_DEPLOY_PORT");
    }

    public static OkHttpClient getHttpClient() {
        return LazyHolder.okHttpClient;
    }

    /**
     * 静态内部类在使用的时候，进行首次加载
     */
    public static class LazyHolder {
        private static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.MINUTES)
                .readTimeout(5, TimeUnit.MINUTES)
                .writeTimeout(5, TimeUnit.MINUTES)
                .build();
    }

    public String doGet(String appSecret, String url,Object param) {
        OkHttpClient okHttpClient = getHttpClient();
        String result = StringUtils.EMPTY;

        try {
            // 使用 HttpUrl.Builder 构建请求 URL
            HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();

            Field[] fields = param.getClass().getDeclaredFields();
            for (java.lang.reflect.Field field : fields) {
                field.setAccessible(true);
                String name = field.getName();

                Object value = field.get(param);
                if(Objects.nonNull(value)) {
                    urlBuilder.addQueryParameter(name, String.valueOf(value));
                }
            }

            String paramStr = objectMapper.writeValueAsString(param);
            Map<String, Object> paramMap = objectMapper.readValue(paramStr, Map.class);
            Map<String, Object> encodedParams = new HashMap<>();
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                encodedParams.put(entry.getKey(), urlEncode(entry.getValue()));
            }

            String sortedParams = encodedParams.entrySet().stream()
                    .filter(entry -> !"signature".equals(entry.getKey()))
                    .filter(entry -> entry.getValue() != null && !ObjectUtils.isEmpty(entry.getValue()))
                    .sorted(Map.Entry.comparingByKey())
                    .map(entry -> entry.getKey() + "=" + entry.getValue())
                    .collect(Collectors.joining("&"));

            String signature = sign(sortedParams, appSecret);
            signature = urlEncode(signature);

            if(StringUtils.isNotBlank(signature)) {
                urlBuilder.addQueryParameter("signature", signature);
            }

            // 创建 Request 对象
            Request request = new Request.Builder()
                    .url(urlBuilder.build())
                    .get()
                    .build();

            Response response = okHttpClient.newCall(request).execute();
            log.info("【HTTP GET】do http get method finish. url = [{}], response = [{}]", url, response);

            if(!response.isSuccessful()) {
                return result;
            }

            ResponseBody body = response.body();
            if(Objects.isNull(body)) {
                return result;
            }

            result = body.string();
        } catch (Exception exception) {
            log.info("【HTTP GET】do http get method error.", exception);
        }

        return result;
    }

    public String doDelete(String appSecret, String url, Object param) {
        OkHttpClient okHttpClient = getHttpClient();
        String result = StringUtils.EMPTY;

        try {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

            // 在遇到未知属性的时候不抛出异常
            objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

            String bodyStr = objectMapper.writeValueAsString(param);

            // 创建请求体
            MediaType mediaType = MediaType.parse("application/json; charset=utf-8");

            RequestBody requestBody = RequestBody.create(mediaType, bodyStr);

            // 创建 Request 对象
            Request request = new Request.Builder()
                    .url(url)
                    .delete(requestBody)
                    .build();

            Response response = okHttpClient.newCall(request).execute();
            log.info("【HTTP DELETE】do http delete method finish. url = [{}], response = [{}]", url, response);

            if(!response.isSuccessful()) {
                return result;
            }

            ResponseBody body = response.body();
            if(Objects.isNull(body)) {
                return result;
            }

            result = body.string();
        } catch (Exception exception) {
            log.info("【HTTP DELETE】do http delete method error.", exception);
        }

        return result;
    }


    public String doPost(String appSecret, String url, Object param) {
        OkHttpClient okHttpClient = getHttpClient();
        String result = StringUtils.EMPTY;

        try {
            String paramStr = objectMapper.writeValueAsString(param);
            Map<String, Object> paramMap = objectMapper.readValue(paramStr, Map.class);

            Map<String, Object> encodedParams = new HashMap<>();
            for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                encodedParams.put(entry.getKey(), urlEncode(entry.getValue()));
            }

            String sortedParams = encodedParams.entrySet().stream()
                    .filter(entry -> !"signature".equals(entry.getKey()))
                    .filter(entry -> entry.getValue() != null && !ObjectUtils.isEmpty(entry.getValue()))
                    .sorted(Map.Entry.comparingByKey())
                    .map(entry -> entry.getKey() + "=" + entry.getValue())
                    .collect(Collectors.joining("&"));

            String signature = sign(sortedParams, appSecret);
            signature = urlEncode(signature);

            if(StringUtils.isNotBlank(signature)) {
                paramMap.put("signature", signature);
            }

            String bodyStr = objectMapper.writeValueAsString(paramMap);

            // 创建请求体
            MediaType mediaType = MediaType.parse("application/json; charset=utf-8");

            RequestBody requestBody = RequestBody.create(mediaType, bodyStr);

            // 创建 Request 对象
            Request request = new Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build();

            try(
                    // 发起请求并获取响应
                    Response response = okHttpClient.newCall(request).execute();

                    // 获取响应体
                    ResponseBody responseBody = response.body()
            ) {
                if(Objects.isNull(responseBody)) {
                    return result;
                }

                result = responseBody.string();
            }
        } catch (Exception exception) {
            log.info("【HTTP POST】do http post method error.", exception);
        }

        return result;
    }

    private String sign(String sortParams, String appSecret) throws Exception{
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        sha256Hmac.init(secretKeySpec);
        byte[] hash = sha256Hmac.doFinal(sortParams.getBytes(StandardCharsets.UTF_8));
        return Base64.encodeBase64String(hash);
    }

    private String urlEncode(Object str) {
        return URLEncoder.encode(str.toString(), StandardCharsets.UTF_8);
    }


}
